//测试用
const Net_createSpriteset = Scene_Map.prototype.createSpriteset;
Scene_Map.prototype.createSpriteset = function () {
    Net_createSpriteset.call(this);
    if (NetMap.needPlacePlayer) {
        NetManager.players.addAll();
    }
    console.time();
}

//同步角色地图数据
Game_Actor.prototype.setupNetMap = function () {
    const { name, level, classId, characterName, characterIndex, faceName, faceIndex } = NetManager.actorMapData;
    this._name = name;
    // this._profile = actor.profile;
    // this._level = level;
    this._characterName = characterName;
    this._characterIndex = characterIndex;
    this._faceName = faceName;
    this._faceIndex = faceIndex;
    this._classId = classId + 1;
    // this._battlerName = battlerName;
}

//同步pve战斗数据
Game_Actor.prototype.setupNetBattle = function (data) {
    const { name, level, classId, battlerName } = data;
    const actor = NetManager.party[name];
    this._name = name;
    this._level = level;
    this._classId = classId + 1;
    this._faceName = actor.faceName;
    this._faceIndex = actor.faceIndex;
    this._battlerName = battlerName;
    NetManager.battleActor[name] = this;
}

//覆盖原函数，使开始游戏玩家位置为服务器保存的位置
Game_Player.prototype.setupForNewGame = function () {
    const mapId = NetManager.actorMapData?.position[0];
    const x = NetManager.actorMapData?.position[1];
    const y = NetManager.actorMapData?.position[2];
    this.reserveTransfer(mapId, x, y, 2, 0);
}

//覆盖原函数，使玩家的行走图数据是用服务器保存的数据
Game_Player.prototype.refresh = function () {
    const { characterName, characterIndex } = NetManager.actorMapData;
    this.setImage(characterName, characterIndex);
    this._followers.refresh();
}

//场所移动后向服务器广播
const Net_performTransfer = Game_Player.prototype.performTransfer;
Game_Player.prototype.performTransfer = function () {
    const oldMapId = $gameMap.mapId() === 0 ? null : $gameMap.mapId();
    const newMapId = this._newMapId;
    Net_performTransfer.call(this);
    const x = $gamePlayer.x;
    const y = $gamePlayer.y;
    const data = { oldMapId, newMapId, x, y };
    //广播地图传送事件
    NetManager.mapServer.emit('transfer', data);
    //向服务器获取新地图所有玩家数据
    NetManager.mapServer.emit('get map player', newMapId);
}

/*
 * 1.移动时向相同地图其他玩家广播移动信息
 * 2.移动时如果有某些net窗口处于显示状态时隐藏该窗口（玩家列表窗口、目标窗口）
 */
const Net_executeMove = Game_Player.prototype.executeMove;
Game_Player.prototype.executeMove = function (direction) {
    Net_executeMove.call(this, direction);
    //玩家列表窗口
    if (SceneManager._scene?._playerListWindow?.visible) {
        SceneManager._scene._playerListWindow.hide();
        SceneManager._scene._playerListWindow.deactivate();
    }
    //目标窗口
    if (SceneManager._scene?._targetWindow.visible) {
        SceneManager._scene._targetWindow.hide();
    }
    //"name": NetManager.actorMapData.name,
    const data = {
        "mapId": $gameMap.mapId(),
        "x": $gamePlayer._x,
        "y": $gamePlayer._y,
    }
    NetManager.mapServer.emit('move', data);
}

//地图刷新增加刷新同屏其他玩家
const Net_map_updateMain = Scene_Map.prototype.updateMain;
Scene_Map.prototype.updateMain = function () {
    Net_map_updateMain.call(this);
    NetManager.players.update();
}

/*
 *1.触摸地图时判断该点是否有其他玩家如果有触发交互
 *2.如果触摸的在某些窗口上，不触发移动（玩家列表、目标窗口）
 */
Scene_Map.prototype.onMapTouch = function () {
    //玩家列表
    if (this?._playerListWindow?.visible) {
        if (this._playerListWindow.contains(TouchInput.x, TouchInput.y)) return;
    }
    //目标窗口  点击该窗口时呼出玩家选项菜单
    if (this?._targetWindow.visible) {
        if (this._targetWindow.contains(TouchInput.x, TouchInput.y)) {
            this._playerCommandWindow.setPlayer(this._targetWindow._actor._name);
            this._playerCommandWindow.activate();
            this._playerCommandWindow.show();
            return;
        }
    }
    const x = $gameMap.canvasToMapX(TouchInput.x);
    const y = $gameMap.canvasToMapY(TouchInput.y);
    if (this.findPlayers(x, y)) {
        return;
    }
    $gameTemp.setDestination(x, y);
}

//地图点击后，寻找点击位置的玩家
Scene_Map.prototype.findPlayers = function (x, y) {
    const players = NetManager.players._data;
    const list = [];
    for (const player of players.entries()) {
        if (player[1].x === x && player[1].y === y) {
            list.push(player[0]);
        }
    }
    if (list.length > 0) {
        if (list.length === 1) {
            this.showTargetWindow(list[0]);
            return true;
        }
        const sprite = players.get(list[0])._sprite;
        const sx = sprite.x;
        const sy = sprite.y;
        this.openPlayerListWindow(list, sx, sy);
        return true;
    }
    return false;
}

//选择地图上的其他玩家后，如果该位置只有一名玩家，直接显示目标信息窗口并设置参数
Scene_Map.prototype.showTargetWindow = function (playerName) {
    if (this._targetWindow.visible) return;
    const player = NetManager.players._data.get(playerName);
    this._targetWindow.setActor(player);
    this._targetWindow.refresh();
    this._targetWindow.show();
}

//如果该位置有多名玩家，则显示玩家列表窗口,该窗口用到情况不是很多，所以没有在加载场景是提前创建
Scene_Map.prototype.openPlayerListWindow = function (list, x, y) {
    if (!this._playerListWindow) {
        this._playerListWindow = new Window_PlayList(list, x, y);
        this.addWindow(this._playerListWindow);
    }
    this._playerListWindow.show(list, x, y);
    this._playerListWindow.activate();
    return;
}

//===============一些地图交互功能的静态类===============
class NetMap {

    static needPlacePlayer = false;
    static message = null;

    //创建socket事件，将在选择角色进入游戏后执行
    static createSocketEvent() {

        const socket = NetManager.mapServer;

        //在线玩家人数刷新
        socket.on("player refresh", (data) => {
            NetManager.playerNum = data;
        })

        //提示信息
        socket.on("tip pop", (data) => {
            SceneManager._scene._mapNameWindow.pop(data)
        })

        //获取角色信息
        socket.on("actor map info", (data) => {
            NetManager.create(data);

            NetManager.netActor().setupNetMap();
        })

        //接受当前地图玩家数据
        socket.on("players info", (data) => {
            console.timeEnd();
            NetManager.players.reset();
            NetManager.players.create(data);
            NetManager.players.addAll();
        })

        //处理玩家进入地图
        socket.on('enter map', (data) => {
            const { name } = data;
            NetManager.players.create([data]);
            NetManager.players.add(name);
        })

        //处理玩家离开地图
        socket.on('leave map', (data) => {
            const { name } = data;
            NetManager.players.remove(name);
        })

        //接受其他玩家移动指令
        socket.on('move', (data) => {
            const players = NetManager.players._data;
            const { x, y } = data;
            if (!players.has(name)) return;
            players.get(name).move(x, y);
        })

        //其他客户端登录
        socket.on('log out', () => {
            location.reload();
        })

        //其他客户端登录
        socket.on('Re login', () => {
            SceneManager._scene._tipWindow.pop("该角色已在其他端登录，已弹出该角色，请重新登陆！");
            setTimeout(() => {
                SceneManager.goto(Scene_Title);
            }, 1000);
        })

        //服务器重启导致的socket断线重连机制引发的错误，强制踢下线，此为暂时解决方案！！
        socket.on('err link', () => {
            socket.disconnect();
            NetManager.mapServer = null;
            SceneManager.goto(Scene_Title);
        })

        //======================交互====================

        //更新队伍信息
        socket.on("updata party", (data) => {
            const partyWindow = SceneManager._scene._partyWindow;
            const tipWindow = SceneManager._scene._mapNameWindow;
            const name = NetManager.actorMapData.name;
            let text;
            NetManager.party = data.member;
            if (partyWindow) {
                partyWindow.refresh();
            }
            if (tipWindow && data.tip) {
                switch (data.tip[0]) {
                    case "1":
                        text = $dataText["1"];
                        SceneManager._scene._mapNameWindow.pop(text);
                        break;
                    case "2":
                        if (data.tip[1] === name) return;
                        text = $dataText["2"].replace(/%1/g, data.tip[1]);
                        SceneManager._scene._mapNameWindow.pop(text);
                        break;
                    case "3":
                        if (data.tip[1] === name) return;
                        text = $dataText["3"].replace(/%1/g, data.tip[1]);
                        SceneManager._scene._mapNameWindow.pop(text);
                        break;
                    case "4":
                        if (data.tip[1] === name) return;
                        text = $dataText["4"].replace(/%1/g, data.tip[1]);
                        SceneManager._scene._mapNameWindow.pop(text);
                        break;
                    case "5":
                        if (data.tip[1] === name) return;
                        text = $dataText["5"].replace(/%1/g, data.tip[1]);
                        SceneManager._scene._mapNameWindow.pop(text);
                        break;
                    default:
                        break;
                }
            }
        })

        //收到组队邀请
        socket.on("party invite", (leaderName) => {
            const text = `收到${leaderName}的组队邀请，是否接受？`
            SceneManager._scene?._confirmWindow.setText(text);
            SceneManager._scene?._confirmWindow.setMode("party");
            SceneManager._scene?._confirmWindow.show();
        })

        //队伍解散
        socket.on("party dissolve", () => {
            NetManager.party = {};
            const partyWindow = SceneManager._scene._partyWindow;
            const tipWindow = SceneManager._scene._mapNameWindow;
            if (partyWindow) partyWindow.refresh();
            if (tipWindow) tipWindow.pop("队伍已解散");

        })

        //战斗准备
        socket.on("battle ready", (data, battleData, seed) => {
            NetManager.setBattleSeed(seed);
            NetManager.battleData = data;
            NetManager.battleMode = "input";
            NetManager.battleAction["name"] = NetManager.actorMapData.name;
            const battleMember = $gameParty.battleMembers();
            for (let i = 0; i < battleMember.length; i++) {
                battleMember[i].setupNetBattle(data[i]);
            }
            $gameTemp.battleCount = $gameParty.battleMembers().length;
            NetBattle.joinBattle(battleData);
        })

        //聊天
        socket.on("chat A", (data) => {
            const { type, message } = data;
            const index = NetMap.message.data.length;
            NetMap.message.data.push(message);
            NetMap.message.all.push(index);
            switch (type) {
                case 0:
                    NetMap.message.world.push(index);
                    break;
                case 1:
                    NetMap.message.map.push(index);
                    break;
                case 2:
                    NetMap.message.party.push(index);
                    break;
                default:
                    break;
            }
            if (SceneManager._scene.constructor.name === "Scene_Chat") {
                SceneManager._scene._chatWindow.refresh();
            }
        })
    }

    static commandParty() {
        // if (NetManager.party) {
        //     const num = Object.keys(NetManager.party).length;
        //     if (num > 5) {
        //         SceneManager._scene._mapNameWindow.pop("队伍已满！");
        //     }
        // }
        // const playerName = SceneManager._scene._playerCommandWindow._player;
        // NetMap.partyInvite(playerName);
        // SceneManager._scene._playerCommandWindow.hide();
    }

    static partyInvite(playerName) {
        NetManager.mapServer.emit('sending party invite', playerName);
    }

    static partyAgree() {
        NetManager.mapServer.emit("party agree", (response) => {
        });
    }

    static partyRefuse() {
        NetManager.mapServer.emit("party refuse");
    }

    static leaveParty() {
        if (!NetManager.party) return;
        NetManager.party = null;
        NetManager.mapServer.emit("leave party");
        const partyWindow = SceneManager._scene._partyWindow;
        if (partyWindow) partyWindow.refresh();
    }

    static iniMessage() {
        NetMap.message = {
            "data": [],
            "all": [],
            "world": [],
            "map": [],
            "party": []
        }
    }

    static sendMessage(message) {
        NetManager.mapServer.emit("chat", message);
    }
}

//===============其他玩家集合的类===============
class Players {
    constructor() {
        this._data = new Map();//当前地图玩家对象，不包括你
        this._playersNum = 1;//当前地图玩家人数，包括你
    }

    reset() {
        this._data = new Map();
        this._playersNum = 1;
    }

    create(data) {
        for (const player of data) {
            const { name, x, y } = player;
            if (name === NetManager.actorMapData.name) continue;
            const character = new Net_Character(player);
            character.locate(x, y);
            this._data.set(name, character);
        }
    }

    add(player) {
        if (!this._data.has(player)) return;
        //只有在地图场景才操作行走图精灵
        if (SceneManager._scene.constructor.name !== "Scene_Map") return;
        const spriteset = SceneManager._scene._spriteset._tilemap;
        const character = this.getCharacter(player);
        const sprite = new Sprite_Character(character);
        const data = character._data;
        sprite.createNameSprite();
        character._sprite = sprite;
        spriteset.addChild(sprite);
    }

    addAll() {
        const spriteset = SceneManager._scene._spriteset._tilemap;
        for (const player of this._data.keys()) {
            const character = this.getCharacter(player);
            const sprite = new Sprite_Character(character);
            const data = character._data;
            sprite.createNameSprite();
            character._sprite = sprite;
            spriteset.addChild(sprite);
        }
        NetMap.needPlacePlayer = false;
    }

    remove(player) {
        if (!this._data.has(player)) return;
        //只有在地图场景才操作行走图精灵
        if (SceneManager._scene.constructor.name === "Scene_Map") {
            const spriteset = SceneManager._scene._spriteset._tilemap;
            const sprite = this._data.get(player)._sprite
            spriteset.removeChild(sprite);
        }
        this._data.delete(player);
    }

    refresh() {
        for (const player of this._data.entries()) {
            player[1].refresh();
        }
    }

    update() {
        for (const player of this._data.entries()) {
            player[1].update();
        }
    }

    getCharacter(playerName) {
        return this._data.get(playerName);
    }
}

//===============其他玩家的人物类===============
class Net_Character extends Game_Character {
    initialize(data) {
        super.initialize();
        this._data = data;
        this.setThrough(true);
        this.refresh();
        // this.createSprite();
    }

    refresh() {
        const { characterName, characterIndex } = this._data;
        this.setImage(characterName, characterIndex);
    }

    createSprite() {
        this._sprite = new Sprite_Character(this);
        this._sprite.createNameSprite();
        this._sprite._nameSprite.setColor("#FFFFFF");
        this._sprite._nameSprite.setName(this._data.name);
        this._sprite._nameSprite.setTitle(this._data.title);
    }

    update() {
        super.update.call(this);
        this.setMoveSpeed($gamePlayer.realMoveSpeed());
        this.setOpacity($gamePlayer.opacity());
        this.setBlendMode($gamePlayer.blendMode());
        this.setWalkAnime($gamePlayer.hasWalkAnime());
        this.setStepAnime($gamePlayer.hasStepAnime());
        this.setDirectionFix($gamePlayer.isDirectionFixed());
        this.setTransparent($gamePlayer.isTransparent());
    };

    move(x, y) {
        const sx = this.deltaXFrom(x);
        const sy = this.deltaYFrom(y);
        if (sx !== 0 && sy !== 0) {
            this.moveDiagonally(sx > 0 ? 4 : 6, sy > 0 ? 8 : 2);
        } else if (sx !== 0) {
            this.moveStraight(sx > 0 ? 4 : 6);
        } else if (sy !== 0) {
            this.moveStraight(sy > 0 ? 8 : 2);
        }
        this.setMoveSpeed($gamePlayer.realMoveSpeed());
    }
}

Sprite_Character.prototype.createNameSprite = function () {
    const nameSprite = new Sprite_PlayerName(this);
    const data = this._character._data;
    nameSprite.setColor("#FFFFFF");
    nameSprite.setName(data.name());
    nameSprite.setTitle(data.title ?? 0);
    this.addChild(nameSprite);
    this._nameSprite = nameSprite;
}

Spriteset_Map.prototype.createCharacters = function () {
    this._characterSprites = [];
    for (const event of $gameMap.events()) {
        this._characterSprites.push(new Sprite_Character(event));
    }
    for (const vehicle of $gameMap.vehicles()) {
        this._characterSprites.push(new Sprite_Character(vehicle));
    }
    for (const follower of $gamePlayer.followers().reverseData()) {
        this._characterSprites.push(new Sprite_Character(follower));
    }
    //添加角色名字
    const player = new Sprite_Character($gamePlayer);
    player._character._data = NetManager.netActor();
    player.createNameSprite();
    player._nameSprite.setColor("#3399FF");
    this._characterSprites.push(player);
    for (const sprite of this._characterSprites) {
        this._tilemap.addChild(sprite);
    }
}

//===============玩家的名字称号精灵类===============
class Sprite_PlayerName extends Sprite {
    initialize(sprite) {
        super.initialize();
        this._characterSprite = sprite;
        this._name = "";
        this._titleId = 0;
        this.createBitmap();//绘制名字
        this.refresh();	//刷新信息
    }

    createBitmap() {
        this.bitmap = new Bitmap(144, 120);
        this.anchor.x = 0.5;
        this.anchor.y = 0.5;
        this.x = 0;
        this.y = -120;
        this.bitmap.fontSize = 20;
    }

    refresh() {
        this.bitmap.clear();
        const name = this._name;
        this.bitmap.drawText(name, 0, 100, 144, 20, 'center');
        this.drawTitle();
    }

    setName(name) {
        this._name = name;
        this.refresh();
    }

    setColor(color) {
        this.bitmap.textColor = color;
        this.refresh();
    }

    setTitle(titleId) {
        this._titleId = titleId;
        this.refresh();
    }

    drawTitle() {
        const titleId = this._titleId;
        if (titleId != 0) {
            const titleName = `title_${titleId}`;
            const bitmap = ImageManager.loadSystem(titleName);
            bitmap.addLoadListener(() => {
                this.bitmap.blt(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 100 - bitmap.height);
            })
        }
    }

}

